package customerEnter.Frame.JDBCDao.UseQuery;

import static com.google.common.collect.Maps.newHashMap;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.jdbc.support.rowset.SqlRowSetMetaData;

import customerEnter.Frame.Annotation.FrameOneToMay;
import customerEnter.Frame.Annotation.FrameOneToOne;
import customerEnter.Frame.Annotation.FramePrimaryKey;
import customerEnter.Frame.DaoDataTransmission.DaoFramePameTransmission;
import customerEnter.Frame.DaoDataTransmission.PagingParametersResult;
import customerEnter.Frame.Enum.AllClassBeanEnum;
import customerEnter.Frame.Enum.FrameOneOrMay;
import customerEnter.Frame.Error.FramErrorProcessing;
import customerEnter.Frame.JDBCDao.Interface.DaoFrameUseTypeInterface;
import customerEnter.Frame.JDBCDao.util.DaoFrameConntroller;
import customerEnter.Frame.Utils.Log4j;
import customerEnter.Frame.bean.FramMappingBeans;
import customerEnter.Frame.bean.FrameBeansModels;
import customerEnter.Frame.bean.FrameMappingField;
import customerEnter.Frame.bean.FrameMappingMayBeans;
import customerEnter.Frame.bean.FrameMappingOneBeans;
import customerEnter.Frame.bean.interfaces.FrameMappingMayBeansInterfaces;
import customerEnter.Frame.bean.interfaces.FrameMappingOneBeansInterfaces;
import customerEnter.Frame.bean.interfaces.FrameMappingOneOrMayBeansInterfaces;
import customerEnter.Frame.scanning.ScanningExtendedConfig;
import customerEnter.Frame.scanning.scanningServer.ProjectScanningOneAndMayModelServer;
import customerEnter.tool.WhetherToEmpty;

/**
 * 一對多和一對一的數據庫映射
 * 
 * 條件： 1在第一個類標註好主鍵 2 在需要反射的屬性對象上標註好對象的關係 3一對多identity 需要寫好值 否做默認為id
 * 
 * 类名称：DaoFrameUseTypeListTImpl 类描述： 创建人：dy 创建时间：2017-4-13 下午3:03:15
 * 
 */
public class DaoFrameUseTypeMayAndOneListTImpl implements DaoFrameUseTypeInterface<List<?>> {

	Map<String, Set<Integer>>	too					= null;
	int							position			= 1;
	Map<String, Integer>		positionMap			= newHashMap();
	Map<Integer, String>		positionMapString	= newHashMap();

	@Override
	public <T, K> List<?> useDaoFrameDataType(DaoFramePameTransmission<T, K> daoFramePameTransmission) {
		initTooMapis(daoFramePameTransmission);
		List<?> list = null;
		try {
			list = NewInstanceValues(daoFramePameTransmission, new FrameBeansModels(), new FramMappingBeans());
		} catch (Exception e) {
			Log4j.Log4JOutError("DaoFrameUseTypeInterface.DaoFrameUseTypeMayAndOneListTImpl :" + e.getMessage());
		}
		return list;
	}

	/**
	 * 初始化相同列的位置
	 */
	public <T, K> void initTooMapis(DaoFramePameTransmission<T, K> daoFramePameTransmission) {
		too = getTables(daoFramePameTransmission);
	}

	/**
	 * 獲取位置 表的順序
	 */
	public void getPosition(Field[] fieldsOld) {
		for (Field field : fieldsOld) {
			field.setAccessible(true);
			FrameOneToMay frameOneToMay = field.getAnnotation(FrameOneToMay.class);
			FrameOneToOne frameOneToOne = field.getAnnotation(FrameOneToOne.class);
			if (!WhetherToEmpty.ObjectWhetherToEmpty(frameOneToMay)
					|| !WhetherToEmpty.ObjectWhetherToEmpty(frameOneToOne)) {
				Field[] fields = null;
				String className = field.getName();
				if (!WhetherToEmpty.ObjectWhetherToEmpty(frameOneToMay)) {
					Class<?> class1 = DaoFrameConntroller.getListT(field);
					fields = class1.getDeclaredFields();
				} else if (!WhetherToEmpty.ObjectWhetherToEmpty(frameOneToOne)) {
					fields = field.getType().getDeclaredFields();
				}
				position++;
				positionMap.put(className, position);
				getPosition(fields);
			}
		}

	}

	@SuppressWarnings("rawtypes")
	public <T, K> void setScanningExtended(DaoFramePameTransmission<T, K> daoFramePameTransmission,
			FrameBeansModels frameBeansModel, Class<?> class1) {
		daoFramePameTransmission.setPagingParametersResult(new PagingParametersResult());
		ScanningExtendedConfig scanningExtendedConfig = new ProjectScanningOneAndMayModelServer();
		position = 1;
		getPosition(class1.getDeclaredFields());
		positionMap.put(class1.getName(), 1);
		for (Entry<String, Integer> entry : positionMap.entrySet()) {
			positionMapString.put(entry.getValue(), entry.getKey());
		}
		scanningExtendedConfig.getFrameBeansModels(class1.getDeclaredFields(), frameBeansModel);
		frameBeansModel.setName(class1.getName());
	}

	/**
	 * 設置表結構和相對應的類結構
	 * 
	 * @throws FramErrorProcessing
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 * @throws InvocationTargetException
	 * 
	 * @throws Exception
	 */

	private <T, K> List<?> NewInstanceValues(DaoFramePameTransmission<T, K> daoFramePameTransmission,
			FrameBeansModels frameBeansModel, FramMappingBeans framMappingBeans) throws FramErrorProcessing,
			SQLException, InstantiationException, IllegalAccessException, InvocationTargetException {
		// 設置基礎數據
		setScanningExtended(daoFramePameTransmission, frameBeansModel, daoFramePameTransmission.cls);
		// 在frameBeansModel 設置第一層
		setFramesListMap(daoFramePameTransmission.sqlRowSet, frameBeansModel);
		// 在frameBeansModel 設置其他層
		setFilesObject(frameBeansModel, daoFramePameTransmission.sqlRowSet);
		// 獲取主表主鍵
		getPrimaryKey(frameBeansModel);
		// 刪除無關數據（主鍵表）
		idenitcaldata(frameBeansModel);
		// 刪除其他無關數據 (其他表)
		idenitcaldataFrameBeans(frameBeansModel);
		// 設置主鍵表（單個）
		setBeanValues(daoFramePameTransmission.cls, frameBeansModel, daoFramePameTransmission);
		// 第一個數據存放
		getFrameBeansFieldIn(frameBeansModel, null, framMappingBeans);
		// 數據轉換成bean
		return InitObject(framMappingBeans, daoFramePameTransmission.cls);
	}

	public List<Object> InitObject(FramMappingBeans framMappingBeans, Class<?> class1) throws InstantiationException,
			IllegalAccessException, InvocationTargetException {

		List<Object> objects = new ArrayList<Object>();
		List<FrameMappingOneOrMayBeansInterfaces> list = framMappingBeans.getBeans();

		for (FrameMappingOneOrMayBeansInterfaces frameMapping : list) {
			Object object = class1.newInstance();
			FrameMappingOneBeansInterfaces frameMappingOne = (FrameMappingOneBeansInterfaces) frameMapping;
			Map<String, FrameMappingField> fMap = frameMappingOne.getFieldValues();
			Field[] fields = object.getClass().getDeclaredFields();
			for (Field field : fields) {
				field.setAccessible(true);
				FrameMappingField frameMappingField = fMap.get(field.getName());
				if (frameMappingField != null) {
					Object object2 = frameMappingField.getValue();
					if (object2 != null) {
						field.set(object, object2);
					} else {
						FramMappingBeans framMappingBeans2 = frameMappingField.getFramMappingBeans();
						if (framMappingBeans2 != null) {
							InitObjectNext(framMappingBeans2, field, object);
						}
					}
				}
			}
			objects.add(object);
		}
		return objects;
	}

	public void InitObjectNext(FramMappingBeans framMappingBeans, Field fieldTop, Object object)
			throws IllegalArgumentException, IllegalAccessException, InstantiationException {
		List<FrameMappingOneOrMayBeansInterfaces> list = framMappingBeans.getBeans();
		for (FrameMappingOneOrMayBeansInterfaces frameMapping : list) {
			if (FrameMappingOneBeans.class.equals(frameMapping.getClass())) {
				FrameMappingOneBeansInterfaces frameMappingOne = (FrameMappingOneBeansInterfaces) frameMapping;
				Object obj = fieldTop.getType().newInstance();
				InitObjectNextForField(frameMappingOne.getFieldValues(), obj);
				fieldTop.set(object, obj);
			} else if (FrameMappingMayBeans.class.equals(frameMapping.getClass())) {
				FrameMappingMayBeansInterfaces frameMappingMay = (FrameMappingMayBeansInterfaces) frameMapping;
				List<FrameMappingOneBeansInterfaces> list2 = frameMappingMay.getFrameMappingOneBeans();
				List<Object> list3 = new ArrayList<Object>();
				for (FrameMappingOneBeansInterfaces frameMappingOne : list2) {
					Object obj = DaoFrameConntroller.getListT(fieldTop).newInstance();
					InitObjectNextForField(frameMappingOne.getFieldValues(), obj);
					list3.add(obj);
				}
				fieldTop.set(object, list3);
			}
		}
	}

	public void InitObjectNextForField(Map<String, FrameMappingField> fMap, Object obj)
			throws IllegalArgumentException, IllegalAccessException, InstantiationException {
		Field[] fields = obj.getClass().getDeclaredFields();
		for (Field field : fields) {
			field.setAccessible(true);
			FrameMappingField frameMappingField = fMap.get(field.getName());
			if (frameMappingField != null) {
				Object object2 = frameMappingField.getValue();
				if (object2 != null) {
					field.set(obj, object2);
				} else {
					FramMappingBeans framMappingBeans2 = frameMappingField.getFramMappingBeans();
					InitObjectNext(framMappingBeans2, field, obj);
				}
			}
		}
	}

	public <T, K> void setFramesListMap(SqlRowSet set, FrameBeansModels frameBeansModel) throws FramErrorProcessing,
			SQLException {
		try {
			set.beforeFirst();
			String className = frameBeansModel.getName();
			while (set.next()) {
				setFilesModel(set, frameBeansModel, className);
			}
			removeSetToo(className);
			removeMapToo(className);
		} catch (Exception e) {
			throw new FramErrorProcessing(e, " DaoFrameUseTypeListTImpl.NewInstanceValues ");
		}
	}

	public <T, K> void setFilesModel(SqlRowSet set, FrameBeansModels frameBeansModels, String in)
			throws FramErrorProcessing {
		Field[] fields = frameBeansModels.getFields();
		Map<String, Object> map = newHashMap();
		for (Field field : fields) {
			if (WhetherToEmpty.ObjectWhetherToEmpty(field)) {
				continue;
			}
			Object objectValue = null;
			String fieldName = field.getName();
			try {
				Set<Integer> lIntegers = too.get(fieldName);
				if (lIntegers == null || lIntegers.size() == 0) {
					objectValue = getResutleObject(set, fieldName, field.getType());
				} else {
					int col = nextToo(lIntegers, false, in);
					objectValue = set.getObject(col);
				}
				map.put(fieldName, objectValue);
			} catch (IllegalArgumentException e1) {
				throw new FramErrorProcessing(e1, "屬性反射錯誤：" + e1.getMessage() + " 屬性名字：" + fieldName + " 屬性值："
						+ objectValue);
			} catch (Exception e) {
				Log4j.Log4jOutInfo("取數據出錯：" + "沒有這個列名字" + fieldName);
			}
		}
		frameBeansModels.getList().add(map);
	}

	public <T, K> void setFilesObject(FrameBeansModels frameBeansModel, SqlRowSet set) throws FramErrorProcessing,
			SQLException {
		Map<String, FrameBeansModels> map2 = frameBeansModel.getFrameBeansMap();
		for (Entry<String, FrameBeansModels> entry : map2.entrySet()) {
			FrameBeansModels frameBeansModels = entry.getValue();
			setFramesListMap(set, frameBeansModels);
			if (!frameBeansModels.getFrameBeansMap().isEmpty()) {
				setFilesObject(frameBeansModels, set);
			}
		}
	}

	private Object getResutleObject(SqlRowSet resultSet, String name, Class<?> class1) throws SQLException {
		Object object = null;
		if (class1 == AllClassBeanEnum.SMint.getClassValue() || class1 == AllClassBeanEnum.BGBigInteger.getClassValue()) {
			object = resultSet.getInt(name);
		} else if (class1 == AllClassBeanEnum.SMboolean.getClassValue()
				|| class1 == AllClassBeanEnum.BGBoolean.getClassValue()) {
			object = resultSet.getBoolean(name);
		} else if (class1 == AllClassBeanEnum.SMbyte.getClassValue()
				|| class1 == AllClassBeanEnum.BGByte.getClassValue()) {
			object = resultSet.getByte(name);
		} else if (class1 == AllClassBeanEnum.SMchar.getClassValue()
				|| class1 == AllClassBeanEnum.BGCharacter.getClassValue()) {
			object = resultSet.getObject(name);
		} else if (class1 == AllClassBeanEnum.SMdouble.getClassValue()
				|| class1 == AllClassBeanEnum.BGDouble.getClassValue()) {
			object = resultSet.getDouble(name);
		} else if (class1 == AllClassBeanEnum.SMfloat.getClassValue()
				|| class1 == AllClassBeanEnum.BGFloat.getClassValue()) {
			object = resultSet.getFloat(name);
		} else if (class1 == AllClassBeanEnum.SMlong.getClassValue()
				|| class1 == AllClassBeanEnum.BGLong.getClassValue()) {
			object = resultSet.getLong(name);
		} else if (class1 == AllClassBeanEnum.SMshort.getClassValue()
				|| class1 == AllClassBeanEnum.BGShort.getClassValue()) {
			object = resultSet.getShort(name);
		} else if (class1 == AllClassBeanEnum.BGBigDecimal.getClassValue()) {
			object = resultSet.getBigDecimal(name);
		} else if (class1 == AllClassBeanEnum.BGString.getClassValue()) {
			object = resultSet.getString(name);
		} else {
			object = resultSet.getObject(name);
		}
		return object;
	}

	/**
	 * 重複的列的位置
	 */
	public <T, K> Map<String, Set<Integer>> getTables(DaoFramePameTransmission<T, K> daoFramePameTransmission) {
		SqlRowSetMetaData sqlRowSetMetaData = daoFramePameTransmission.sqlRowSet.getMetaData();
		String[] str = sqlRowSetMetaData.getColumnNames();
		Map<String, String[]> map = newHashMap();
		Map<String, Set<Integer>> too = newHashMap();
		int i = 1;
		for (String string : str) {
			String[] isString = map.get(string);
			if (isString != null && isString.length > 0) {
				Set<Integer> list = too.get(isString[0]);
				if (list == null) {
					list = new HashSet<Integer>();
				}
				if (string.equals(isString[0])) {
					list.add(i);
					String str1 = isString[1];
					list.add(Integer.parseInt(str1));
					too.put(isString[0], list);
				}
			} else {
				String[] strings = { string, i + "" };
				map.put(string, strings);
			}
			i++;
		}
		return too;
	}

	/**
	 * 獲取主表主鍵
	 */
	public void getPrimaryKey(FrameBeansModels frameBeansModel) {
		Field[] fields = frameBeansModel.getFields();
		for (Field field : fields) {
			field.setAccessible(true);
			if (field.getAnnotation(FramePrimaryKey.class) != null) {
				frameBeansModel.setPrimaryKey(field.getName());
				break;
			}
		}
	}

	/**
	 * 選擇刪除 主鍵單表數據 根據主鍵策略
	 * 
	 * @throws FramErrorProcessing
	 */
	public void idenitcaldata(FrameBeansModels frameBeansModel) throws FramErrorProcessing {
		DaoFrameConntroller.getIdenticalData(frameBeansModel, frameBeansModel.getPrimaryKey());
	}

	/**
	 * 選擇刪除 根據主鍵策略
	 * 
	 * @throws FramErrorProcessing
	 */
	public void idenitcaldataFrameBeans(FrameBeansModels frameBeansModel) throws FramErrorProcessing {
		Map<String, FrameBeansModels> map = frameBeansModel.getFrameBeansMap();
		for (Entry<String, FrameBeansModels> entry : map.entrySet()) {
			FrameBeansModels frameBeansModels = entry.getValue();
			DaoFrameConntroller.getIdenticalData(frameBeansModels, frameBeansModels.getPrimaryKey());
			if (!frameBeansModels.getFrameBeansMap().isEmpty()) {
				idenitcaldataFrameBeans(frameBeansModels);
			}
		}
	}

	public int nextToo(Set<Integer> set, boolean isRemove, String className) {
		if (set == null) {
			return 0;
		}
		Integer[] integers = new Integer[set.size()];
		int js = 0;
		for (Integer integer : set) {
			integers[js] = integer;
			js++;
		}
		Integer[] numbers = bubbleSort(integers);
		Map<String, Integer> map = newHashMap();
		for (int i = 0; i < numbers.length; i++) {
			map.put(positionMapString.get(i + 1), numbers[i]);
		}
		if (map.get(className) == null) {
			return 0;
		}
		int in = map.get(className);

		if (isRemove) {
			Iterator<Integer> iterator = set.iterator();
			while (iterator.hasNext()) {
				Integer ins = iterator.next();
				if (in == ins) {
					iterator.remove();
					break;
				}
			}
		}
		return in;
	}

	public Integer[] bubbleSort(Integer[] numbers) {
		int temp = 0;
		int size = numbers.length;
		for (int i = 0; i < size - 1; i++) {
			for (int j = 0; j < size - 1 - i; j++) {
				if (numbers[j] > numbers[j + 1]) // 交换两数位置
				{
					temp = numbers[j];
					numbers[j] = numbers[j + 1];
					numbers[j + 1] = temp;
				}
			}
		}
		return numbers;
	}

	/**
	 * 刪除
	 */
	public void removeSetToo(String in) {
		for (Entry<String, Set<Integer>> entry : too.entrySet()) {
			nextToo(entry.getValue(), true, in);
		}
	}

	/**
	 * 刪除
	 */
	public void removeMapToo(String in) {
		int key = 0;
		for (Entry<Integer, String> entry : positionMapString.entrySet()) {
			if (in.equals(entry.getValue())) {
				key = entry.getKey();
				break;
			}
		}
		positionMapString.remove(key);
		Integer[] integers = new Integer[positionMapString.size()];
		int ins = 0;
		for (Entry<Integer, String> entry : positionMapString.entrySet()) {
			integers[ins] = entry.getKey();
			ins++;
		}
		Map<Integer, String> map = newHashMap();
		bubbleSort(integers);
		for (int i = 0; i < integers.length; i++) {
			String string = positionMapString.get(integers[i]);
			map.put(i + 1, string);
		}
		positionMapString.clear();
		positionMapString.putAll(map);
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public <T, K> void setBeanValues(Class<?> class1, FrameBeansModels frameBeansModels,
			DaoFramePameTransmission<T, K> daoFramePameTransmission) throws FramErrorProcessing {
		List<Map<String, Object>> list = frameBeansModels.getList();
		Object object = null;
		List list2 = new ArrayList<Object>();
		try {
			for (Map<String, Object> map : list) {
				object = class1.newInstance();
				Field[] fields = class1.getDeclaredFields();
				for (Field field : fields) {
					field.setAccessible(true);
					String beanName = field.getName();
					Object object2 = map.get(beanName);
					try {
						field.set(object, object2);
					} catch (Exception e) {
						Log4j.Log4jOutInfo("取數據出錯：" + "bean數據集合沒有這個列名字" + beanName);
					}
				}
				list2.add(object);
			}
		} catch (Exception e) {
			throw new FramErrorProcessing(e, "實例化對象出錯");
		}
		daoFramePameTransmission.DaoFramelistOther = list2;
	}

	public String splitPoints(String str) {
		if (str.contains(".")) {
			String strs[] = str.split("\\.");
			return strs[strs.length - 1];
		} else {
			return str;
		}
	}

	/**
	 * 獲取屬性組件
	 */
	public void getFrameBeansFieldIn(FrameBeansModels frameBeansModels, Map<String, Object> ObjectValue,
			FramMappingBeans framMappingBeans) {
		List<FrameMappingOneOrMayBeansInterfaces> list = framMappingBeans.getBeans();
		List<Map<String, Object>> list2 = frameBeansModels.getList();
		if (frameBeansModels.getFrameOneOrMay() == null) {
			for (Map<String, Object> map : list2) {
				list.add(setFrameBesnsMaps(frameBeansModels, map, new FrameMappingOneBeans()));
			}
		} else if (FrameOneOrMay.May.equals(frameBeansModels.getFrameOneOrMay())) {
			FrameOneToMay frameOneToMay = frameBeansModels.getFrameOneToMay();
			String primaryKey = splitPoints(frameOneToMay.mayColumn());
			String toColumn = splitPoints(frameOneToMay.oneColumn());
			Object obj = ObjectValue.get(toColumn);
			FrameMappingMayBeansInterfaces frameMappingMay = new FrameMappingMayBeans();
			List<FrameMappingOneBeansInterfaces> frameMappingOneBeansList = frameMappingMay.getFrameMappingOneBeans();
			for (Map<String, Object> map : list2) {
				Object object = map.get(primaryKey);
				if (obj.equals(object)) {
					frameMappingOneBeansList.add(setFrameBesnsMaps(frameBeansModels, map, new FrameMappingOneBeans()));
				}
				list.add(frameMappingMay);
			}
		} else {
			FrameOneToOne frameOneToOne = frameBeansModels.getFrameOneToOne();
			String primaryKey = splitPoints(frameOneToOne.columnPrimaryKey());
			String toColumn = splitPoints(frameOneToOne.ToColumn());
			Object obj = ObjectValue.get(toColumn);

			for (Map<String, Object> map : list2) {
				Object object = map.get(primaryKey);
				if (obj.equals(object)) {
					list.add(setFrameBesnsMaps(frameBeansModels, map, new FrameMappingOneBeans()));
					break;
				}
			}

		}
	}

	public FrameMappingOneBeansInterfaces setFrameBesnsMaps(FrameBeansModels frameBeansModels, Map<String, Object> map,
			FrameMappingOneBeansInterfaces frameMappingOne) {

		for (Entry<String, Object> entry : map.entrySet()) {
			FrameMappingField field = new FrameMappingField();
			String key = entry.getKey();
			field.setKey(key);
			field.setValue(entry.getValue());
			frameMappingOne.getFieldValues().put(key, field);
		}
		Map<String, FrameBeansModels> frameBeans = frameBeansModels.getFrameBeansMap();
		if (!frameBeans.isEmpty()) {
			for (Entry<String, FrameBeansModels> entry : frameBeans.entrySet()) {
				FrameMappingField field = new FrameMappingField();
				String key = splitPoints(entry.getKey());
				field.setKey(key);
				FramMappingBeans framMappingBeans2 = new FramMappingBeans();
				FrameBeansModels frameBeansModels2 = entry.getValue();
				getFrameBeansFieldIn(frameBeansModels2, map, framMappingBeans2);
				field.setFramMappingBeans(framMappingBeans2);
				frameMappingOne.getFieldValues().put(key, field);
			}
		}
		return frameMappingOne;
	}
}
